////////////////////////////////////////////////////////////////////////////
//	VectorMath.h
//		Templated class that contains 3 components to represent a 3d Vector,
//		with all the overloaded operators and functions needed to perform
//		vector x vector or vector x scalar calculations.
//
//	Author:					Daniel Lima - April 2012
/////////////////////////////////////////////////////////////////////////////

#ifndef VECTOR_MATH_H_
#define VECTOR_MATH_H_

// For square root
#include <cmath>

// C3dVector class
// It's a template so we can have vectors of all types
// of variables (ints, floats, chars, etc)
template<class type>
class C3dVector
{
	// The 3 vector components
	type m_xComponent;
	type m_yComponent;
	type m_zComponent;

public:
	// Constructors
	C3dVector(void);
	C3dVector(type x, type y, type z);
	C3dVector(const C3dVector& vec);

	// Assignment operator
	const C3dVector& operator=(const C3dVector& vec);

	// Addition and subtraction
	C3dVector operator+(const C3dVector& vec);
	C3dVector operator-(const C3dVector& vec);

	// Scalar multiplication
	C3dVector operator*(const type& scalar);
	// Scalar division
	C3dVector operator/(const type& scalar);

	// Dot product
	type DotProduct(const C3dVector& vec);
	// Cross product
	C3dVector operator*(const C3dVector& vec);

	// Magnitude
	type GetMagnitude(void);
	// Normalize
	void Normalize(void);

	// Accessors for the components
	inline const type X(void) const { return m_xComponent; }
	inline const type Y(void) const { return m_yComponent; }
	inline const type Z(void) const { return m_zComponent; }
};

// Constructors
template<class type>
C3dVector<type>::C3dVector(void)
	: m_xComponent(0), m_yComponent(0), m_zComponent(0) {}

template<class type>
C3dVector<type>::C3dVector(type x, type y, type z)
	: m_xComponent(x), m_yComponent(y), m_zComponent(z) {}


template<class type>
C3dVector<type>::C3dVector(const C3dVector& vec)
	: m_xComponent(vec.X()), m_yComponent(vec.Y()), m_zComponent(vec.Z()) {}


// Assignment operator
template<class type>
const C3dVector<type>& C3dVector<type>::operator=(const C3dVector& vec)
{
	// Paranoid check
	if(this != &vec)
	{
		m_xComponent = vec.X();
		m_yComponent = vec.Y();
		m_zComponent = vec.Z();
	}
	return *this;
}

// Addition and subtraction
template<class type>
C3dVector<type> C3dVector<type>::operator+(const C3dVector& vec)
{
	return C3dVector<type>(X() + vec.X(), Y() + vec.Y(), Z() + vec.Z());
}

template<class type>
C3dVector<type> C3dVector<type>::operator-(const C3dVector& vec)
{
	return C3dVector<type>(X() - vec.X(), Y() - vec.Y(), Z() - vec.Z());
}

// Scalar multiplication
template<class type>
C3dVector<type> C3dVector<type>::operator*(const type& scalar)
{
	return C3dVector<type>(X() * scalar, Y() * scalar, Z() * scalar);
}

// Scalar division
template<class type>
C3dVector<type> C3dVector<type>::operator/(const type& scalar)
{
	return C3dVector<type>(X() / scalar, Y() / scalar, Z() / scalar);
}

// Dot product
template<class type>
type C3dVector<type>::DotProduct(const C3dVector& vec)
{
	return ((X() * vec.X()) + (Y() * vec.Y()) + (Z() * vec.Z()));
}
// Cross product
template<class type>
C3dVector<type> C3dVector<type>::operator*(const C3dVector& vec)
{
	C3dVector<type> vecCrossed;
	vecCrossed.m_xComponent = (Y() * vec.Z()) - (Z() * vec.Y());
	vecCrossed.m_yComponent = (Z() * vec.X()) - (X() * vec.Z());
	vecCrossed.m_zComponent = (X() * vec.Y()) - (Y() * vec.X());

	return vecCrossed;
}

// Magnitude
template<class type>
type C3dVector<type>::GetMagnitude(void)
{
	return sqrt((X() * X() + Y() * Y() + Z() * Z()));
}

// Normalize
template<class type>
void C3dVector<type>::Normalize(void)
{
	type Norm = GetMagnitude();
	m_xComponent /= Norm;
	m_yComponent /= Norm;
	m_zComponent /= Norm;
}


#endif